package encrypter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;

import com.ipaulpro.afilechooser.utils.FileUtils;

public class Encrypter {

	protected static final Encrypter INSTANCE = new Encrypter();

	protected Encrypter() {

	}

	public static Encrypter get() {
		return INSTANCE;
	}

	/**
	 * @param file
	 *            a encriptar
	 * @param date
	 *            en la cual sera posible desencriptar
	 * @param newFile
	 *            vacio que sera el que contenga la encriptacion
	 */
	public void encrypt(File file, Calendar date, File newFile) {
		this.addDate(file, date);
		byte[] bFile = this.readFile(file);
		this.encrypt(bFile, date);
		this.writeFile(bFile, newFile);
	}

	public void encrypt(File file, Calendar date) {
		this.encrypt(file, date, file);
	}

	/**
	 * @param file
	 *            a saber si se puede desencriptar
	 * @param currentDate
	 *            Momento del tiempo actual
	 * @return
	 */
	public boolean canDecrypt(File file, Calendar currentDate) {
		return currentDate.compareTo(this.getDateFromEncryptedFile(file)) >= 0;
	}

	/**
	 * @param file
	 *            a desencriptar
	 * @param newFile
	 *            vacio que sera el desencriptado
	 */
	public void decrypt(File file, File newFile) {
		byte[] bFile = this.removeDate(file);
		this.decrypt(bFile);
		this.writeFile(bFile, newFile);
	}

	public void decrypt(File file) {
		this.decrypt(file, file);
	}

	protected byte[] removeDate(File file) {
		byte[] bFile = this.readFile(file);
		byte[] bNew = new byte[bFile.length - this.getDateBytesLength()];
		for (int i = 0; i < bFile.length - this.getDateBytesLength(); i++) {
			bNew[i] = bFile[i];
		}
		return bNew;
	}

	protected Calendar getDateFromEncryptedFile(File file) {
		Calendar date = Calendar.getInstance();
		byte[] bf = this.readFile(file);
		int i = bf.length;
		date.set(bf[--i] + 2000, bf[--i], bf[--i], bf[--i], bf[--i], bf[--i]);
		return date;
	}

	protected byte[] readFile(String file) throws IOException {
		return readFile(new File(file));
	}

	protected int getDateBytesLength() {
		return 6;
	}

	protected void addDate(File file, Calendar date) {
		byte[] b = new byte[this.getDateBytesLength()];
		b[0] = (byte) date.get(Calendar.SECOND);
		b[1] = (byte) date.get(Calendar.MINUTE);
		b[2] = (byte) date.get(Calendar.HOUR_OF_DAY);
		b[3] = (byte) date.get(Calendar.DAY_OF_MONTH);
		b[4] = (byte) date.get(Calendar.MONTH);
		b[5] = (byte) (date.get(Calendar.YEAR) - 2000);
		try {
			FileOutputStream output = new FileOutputStream(
					file.getAbsolutePath(), true);
			try {
				output.write(b);
			} finally {
				output.close();
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	protected byte[] readFile(File file) {
		FileInputStream fileInputStream = null;

		byte[] bFile = new byte[(int) file.length()];

		try {
			// convert file into array of bytes
			fileInputStream = new FileInputStream(file);
			fileInputStream.read(bFile);
			fileInputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bFile;
	}

	protected void writeFile(byte[] bFile, File newFile) {
		try {
			// convert array of bytes into file
			FileOutputStream fileOuputStream = new FileOutputStream(newFile);
			fileOuputStream.write(bFile);
			fileOuputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected void encrypt(byte[] bFile, Calendar date) {
		for (int i = 0; i < bFile.length - this.getDateBytesLength(); i++) {
			bFile[i] = (byte) -bFile[i];
		}
	}

	protected void decrypt(byte[] bFile) {
		for (int i = 0; i < bFile.length - this.getDateBytesLength(); i++) {
			bFile[i] = (byte) -bFile[i];
		}
	}

}
